/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.jms;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Enumeration;

import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageNotReadableException;
import javax.jms.MessageNotWriteableException;
/**
   This class implements the Message interface specified in the JMS
   specification.
   
   @author Shrideep Pallickara
   $Revision$
   $Date$
*/

public class JmsMessage implements Message {
  
  /** The header associated with every Jms Message */
  JmsHeader jmsHeader;

  /** The properties associated with every JMS Message */
  JmsProperties jmsProperties;

  /** This variable indicates wether the properties can be modified. Once the
      properties have been initialized, after being sent over the protocol 
      stack, these properties should be immutable. Thus it should start off as
      true (only once) and false everywhere else.*/
  private boolean readOnlyProperties;
  
  /** Indicates wether the body is read only */
  private boolean readOnlyBody=true;
 
  /** Indicates wether the body is write only */
  private boolean writeOnlyBody=true;

  public JmsMessage() {
    jmsHeader = new JmsHeader();
    jmsProperties = new JmsProperties();
  }
  
  public String getJMSMessageID() throws JMSException {
    return jmsHeader.getJMSMessageID();
  }
  
  public void setJMSMessageID(String id) throws JMSException {
    jmsHeader.setJMSMessageID(id);
  }
  
  public long getJMSTimestamp() throws JMSException {
    return jmsHeader.getJMSTimestamp();
  }
  
  public void setJMSTimestamp(long timestamp) throws JMSException {
    jmsHeader.setJMSTimestamp(timestamp);
  }
  
  public byte[] getJMSCorrelationIDAsBytes() throws JMSException {
    return jmsHeader.getJMSCorrelationIDAsBytes();
  }
  
  public void setJMSCorrelationIDAsBytes(byte[] correlationID) 
    throws JMSException {
    jmsHeader.setJMSCorrelationIDAsBytes(correlationID); 
  }
  
  public String getJMSCorrelationID() throws JMSException {
    return jmsHeader.getJMSCorrelationID();
  }
  
  public void setJMSCorrelationID(String correlationID) throws JMSException {
    jmsHeader.setJMSCorrelationID(correlationID);
  }
  
  public Destination getJMSReplyTo() throws JMSException {
    return jmsHeader.getJMSReplyTo();
  }
  
  public void setJMSReplyTo(Destination replyTo) throws JMSException {
    jmsHeader.setJMSReplyTo(replyTo);
      }
  
  public Destination getJMSDestination() throws JMSException {
    return jmsHeader.getJMSDestination();
  }
  
  public void setJMSDestination(Destination destination) throws JMSException {
    jmsHeader.setJMSDestination(destination);
  }
  
  public int getJMSDeliveryMode() throws JMSException {
    return jmsHeader.getJMSDeliveryMode();
  }
  
  public void setJMSDeliveryMode(int deliveryMode) throws JMSException {
    jmsHeader.setJMSDeliveryMode(deliveryMode);
  }
  
  public boolean getJMSRedelivered() throws JMSException {
    return jmsHeader.getJMSRedelivered();
  }
  
  public void setJMSRedelivered(boolean redelivered) throws JMSException {
    jmsHeader.setJMSRedelivered(redelivered);
  }
  
  public String getJMSType() throws JMSException {
    return jmsHeader.getJMSType();
  }
  
  public void setJMSType(String type) throws JMSException {
    jmsHeader.setJMSType(type);
  }
  
  public long getJMSExpiration() throws JMSException {
    return jmsHeader.getJMSExpiration();
  }

  public void setJMSExpiration(long expiration) throws JMSException {
    jmsHeader.setJMSExpiration(expiration);
  }
  
  public int getJMSPriority() throws JMSException {
    return jmsHeader.getJMSPriority();
  }
  
  public void setJMSPriority(int priority) throws JMSException {
    jmsHeader.setJMSPriority(priority);
  }
  
  public  void clearProperties() throws JMSException {
    jmsProperties.clearProperties();
  }
  
  public boolean propertyExists(String name) throws JMSException {
    return jmsProperties.propertyExists(name);
  }
  
  public boolean getBooleanProperty(String name) throws JMSException {
    return jmsProperties.getBooleanProperty(name);
  }
  
  public  void  setBooleanProperty(String name, boolean value) 
    throws JMSException {
    testWriteProperties();
    jmsProperties.setBooleanProperty(name, value); 
  }
  
  public byte getByteProperty(String name) throws JMSException {
    return jmsProperties.getByteProperty(name);
  }
  
  public void setByteProperty(String name, byte value) throws JMSException {
    testWriteProperties();
    jmsProperties.setByteProperty(name, value);
  }
  
  public short getShortProperty(String name) throws JMSException {
    return jmsProperties.getShortProperty(name);
  }
  
  public void setShortProperty(String name, short value) throws JMSException {
    testWriteProperties();
    jmsProperties.setShortProperty(name, value);
  }

  public int getIntProperty(String name) throws JMSException {
    return jmsProperties.getIntProperty(name);
  }
  
  public void setIntProperty(String name, int value) throws JMSException {
    testWriteProperties();
    jmsProperties.setIntProperty(name, value);
  }
  
  public long getLongProperty(String name) throws JMSException {
    return jmsProperties.getLongProperty(name);
  }
  
  public void setLongProperty(String name, long value) throws JMSException {
    testWriteProperties();
    jmsProperties.setLongProperty(name, value);
  }
  
  public float getFloatProperty(String name) throws JMSException {
    return jmsProperties.getFloatProperty(name);
  }
  
  public void setFloatProperty(String name, float value) throws JMSException {
    testWriteProperties();
    jmsProperties.setFloatProperty(name, value);
  }
  
  public double getDoubleProperty(String name) throws JMSException {
    return jmsProperties.getDoubleProperty(name);
  }
  
  public void  setDoubleProperty(String name, double value) 
    throws JMSException {
    testWriteProperties();
    jmsProperties.setDoubleProperty(name, value);
  }
  
  public String getStringProperty(String name) throws JMSException {
    return jmsProperties.getStringProperty(name);
  }
  
  public void setStringProperty(String name,String value) throws JMSException{
    testWriteProperties();
    jmsProperties.setStringProperty(name, value);
  }
  
  public Object getObjectProperty(String name) throws JMSException {
    return jmsProperties. getObjectProperty(name);
  }
  
  public void setObjectProperty(String name, Object value)
    throws JMSException {
    testWriteProperties();
    jmsProperties.setObjectProperty(name, value);
  }

  public Enumeration getPropertyNames() throws JMSException {
    return jmsProperties.getPropertyNames();
  }
  
  public void clearBody() throws JMSException {
    
  }

  
  public void acknowledge()  throws JMSException {
    
  }
  
  protected void testWriteBody() throws MessageNotWriteableException {
    /** Throw MessageNotWriteableException if its not allowed to write */
    if (!writeOnlyBody) {
      throw new MessageNotWriteableException("The Message Body is " +
					     "READY Only");
    }
  }
  
  protected void testReadBody() throws MessageNotReadableException {
    /** Throw MessageNotWriteableException if its not allowed to write */
    if (!readOnlyBody) {
      throw new MessageNotReadableException("The Message Body is " +
					     "Write Only");
    }
  }
  
  protected void testWriteProperties() throws MessageNotWriteableException {
    /** Throw MessageNotWriteableException if its not allowed to write */
    if (readOnlyProperties)
      throw new MessageNotWriteableException("The Message Properties are " +
					     " READY Only");
  }

  protected void setBodyAndPropertyAsReadOnly() {
    readOnlyBody = true;
    readOnlyProperties = true;
  }

  public byte[] getBytes() {
    ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
    DataOutputStream dout = new DataOutputStream(baOutputStream);
    byte[] marshalledBytes= null;
    try {
      byte[] jmsHeaderBytes = jmsHeader.getBytes();
      byte[] jmsPropertyBytes = jmsProperties.getBytes();
      
      /** Marshall header byte stream first */
      dout.writeInt(jmsHeaderBytes.length);
      dout.write(jmsHeaderBytes);
      
      /** Marshall the property byte stream next */
      dout.writeInt(jmsPropertyBytes.length);
      dout.write(jmsPropertyBytes);
      
      dout.flush();
      marshalledBytes = baOutputStream.toByteArray();
    } catch (IOException ioe) {
      System.out.println("JmsMessage: Error while marshalling Message bytes");
    } /** end try-catch block*/

    return marshalledBytes;
  }

  public void unmarshallJmsMessage(byte[] messageBytes) {
    ByteArrayInputStream baInputStream = 
      new ByteArrayInputStream(messageBytes);
    DataInputStream din = new DataInputStream(baInputStream);
    try {
      /** Unmarshall the header bytes */
      int headerLength = din.readInt();
      byte[] headerBytes = new byte[headerLength];
      din.readFully(headerBytes);
      jmsHeader = new JmsHeader(headerBytes);
      
      /** Unmarshall the properties associated with this message */
      int propertyLength = din.readInt();
      byte[] propertyBytes = new byte[propertyLength];
      din.readFully(propertyBytes);
      jmsProperties = new JmsProperties(propertyBytes);
    } catch (IOException ioe) {
      System.out.println("JmsMessage: Error unmarshalling message bytes");
    }
  }
  
  public String toString() {
    String stringRep = jmsHeader.toString() + "\n" + jmsProperties.toString();
    return stringRep;
  }
  
}






